<?php
/**
 * 配送区域相关服务
 * Created by PhpStorm.
 * User: poptser@foxmail.com
 * Date: 2018/1/23
 * Time: 10:24
 */
namespace App\Services\Address;


use App\Repositories\Address\DeliverRegionCoordinatesRepositoryEloquent;
use App\Repositories\Address\DeliverRegionRepositoryEloquent;
use App\Repositories\Address\RegionRepositoryEloquent;
use App\Repositories\Address\UserAddressRepositoryEloquent;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;


class DeliveryAreaService{

    protected $deliverRegionCoordinates;
    protected $deliverRegion;

    protected $addressService;
    public function __construct(DeliverRegionCoordinatesRepositoryEloquent $deliverRegionCoordinates,
                                DeliverRegionRepositoryEloquent $deliverRegion,
                                AddressService $addressService){
        $this->deliverRegionCoordinates = $deliverRegionCoordinates;
        $this->deliverRegion = $deliverRegion;

        $this->addressService = $addressService;
    }

    /**
     * 根据地址ID获取所属配送区
     * @param int $AddressId
     * @return mixed
     */
    public function getDeliveryAreaByAddressId(int $AddressId){

        $addressInfo = $this->addressService->getAddress($AddressId);

        $longitude_repair = $this->addressService->checkAddressRepair($addressInfo['sign_building'],$addressInfo['district_id']);
        //组装经纬度数组
        if($longitude_repair){
            $longitudeAndLatitude = $longitude_repair;
        }else{
            $longitudeAndLatitude = $this->addressService->repairLongitudeAndLatitude($addressInfo);
        }
        $deliveryInfo = $this->getDeliveryAreaByLongitudeAndLatitude(
            $longitudeAndLatitude['longitude'],$longitudeAndLatitude['latitude']);
        return $deliveryInfo;
    }

    /**
     * 根据地址获取所属配送区域
     * @param string $Address
     * @param string $City
     * @return mixed
     */
    public function getDeliveryAreaByAddress(string $Address,string $City = '广州'){
        $addressInfo = $this->addressService->addressToGps($Address,$City);
        $deliveryInfo = $this->getDeliveryAreaByLongitudeAndLatitude($addressInfo['longitude'],
            $addressInfo['latitude']);
        return $deliveryInfo;
    }


    /**
     * 根据经纬度获取所属配送区
     * @param string $Longitude
     * @param string $Latitude
     * @return mixed
     */
    public function getDeliveryAreaByLongitudeAndLatitude(string $Longitude, string $Latitude){

        //获取配送方式集合
        $distributionMode = $this->getDistributionMode();
        //合成配送区域坐标集合
        $polygonAll = $this->getAllDeliveryArea($distributionMode);

        foreach ($polygonAll as $polygonValue){    //所有配送区域
            //所有配送区域方式组
            foreach ($polygonValue as $key=>$value){    //单个配送区域
                $free = [];
                foreach ($value as $k=>$v){         //生成单个配送区域坐标范围
                    $free[$k]=[
                        'lat'=>$v['lat'],
                        'lng'=>$v['lng']
                    ];
                    $nowModeId = $v['mode_id'];
                    $nowModeKey= $v['modeKey'];
                    $nowWid = $v['wid'];
                    $nowName = $v['name'];
                    $nowStartPrice = $v['start_price'];
                }
                if(count($free)>0){
                    $data=$this->isPointInPolygon($free,$Longitude,$Latitude);
                    if($data){
                        $regionData['price'] = (float)$nowStartPrice;
                        $regionData['name'] = "free";
                        $regionData['name_true'] = $nowName;
                        if($distributionMode[$nowModeKey]->arrival_type==0){
                            $regionData['prescription'] = "3小时";
                        }else{
                            $regionData['prescription'] = "24小时";
                        }
                        $regionData['wid']=$nowWid;
                        $regionData['wid_name']=DB::table('warehouse')->where(['id'=>$nowWid])->value('name');
                        $regionData['is_day']=$distributionMode[$nowModeKey]->arrival_type;
                        $regionData['wdr_id'] = $key;
                        $regionData['mode_id'] =  $nowModeId;

                        $returnData['code'] =  100;
                        $returnData['msg'] =  '成功';
                        $returnData['data'] =  $regionData;
                        return $returnData;
                    }
                    unset($free);
                    unset($data);
                }
            }
        }
        $res = ['error'=>1,'msg'=>'this address not in delivery area','code'=>1];
        return $res;   //已超区
    }
    /**
     * 根据经纬度组获取所属配送区 批量判断
     * @param array $longitudeAndLatitude
     * @return array
     */
    public function getDeliveryAreaByLongitudeAndLatitudeList(array $longitudeAndLatitude){
        //获取配送方式集合
        $distributionMode = $this->getDistributionMode();
        //合成配送区域坐标集合
        $polygonAll = $this->getAllDeliveryArea($distributionMode);


        $returnData = [];
        foreach ($polygonAll as $polygonValue){    //所有配送区域
            //所有配送区域方式组
            foreach ($polygonValue as $key=>$value){    //单个配送区域
                $free = [];
                foreach ($value as $k=>$v){         //生成单个配送区域坐标范围
                    $free[$k]=[
                        'lat'=>$v['lat'],
                        'lng'=>$v['lng']
                    ];
                    $nowModeId = $v['mode_id'];
                    $nowModeKey= $v['modeKey'];
                    $nowWid = $v['wid'];
                    $nowName = $v['name'];
                    $nowStartPrice = $v['start_price'];
                }
                if(count($free)>0){

                    foreach ($longitudeAndLatitude as $key_gps=>$value_gps){
                        $data=$this->isPointInPolygon($free,$value_gps['longitude'],
                            $value_gps['latitude']);
                        if($data){
                            $regionData['price'] = (float)$nowStartPrice;
                            $regionData['name'] = "free";
                            $regionData['name_true'] = $nowName;
                            if($distributionMode[$nowModeKey]->arrival_type==0){
                                $regionData['prescription'] = "3小时";
                            }else{
                                $regionData['prescription'] = "24小时";
                            }
                            $regionData['wid']=$nowWid;
                            $regionData['wid_name']=DB::table('warehouse')->where(['id'=>$nowWid])->value('name');
                            $regionData['is_day']=$distributionMode[$nowModeKey]->arrival_type;
                            $regionData['wdr_id'] = $key;
                            $regionData['mode_id'] =  $nowModeId;
                            $returnData[$key_gps] =  $regionData;
                        }
                        unset($data);
                    }
                    unset($free);

                }
            }
        }
        $returnDataAll = [];
        foreach ($longitudeAndLatitude as $key_gps=>$value_gps){
            if(!empty($returnData[$key_gps])){
                $returnDataAll[] = $returnData[$key_gps];
            }else{
                $returnDataAll[] = ['error'=>1,'msg'=>'this address not in delivery area','code'=>1];
            }
        }


        return $returnDataAll;   //
    }


    /**
     * 获取配送方式合集
     * @return \Illuminate\Support\Collection|mixed
     */
    private function getDistributionMode(){
        $distribution_mode=Cache::get('distribution_mode_data');
        if(empty($distribution_mode)){
            $distribution_mode = DB::table('distribution_mode')->
            where(['state'=>0])->get();
            if($distribution_mode){
                Cache::put('distribution_mode_data',$distribution_mode,60);
                return $distribution_mode;
            }
        }else{
            return $distribution_mode;
        }
    }


    /**
     * 获取所有的配送区域坐标点集合
     * @param $distributionMode
     * @return array|mixed
     */
    private function getAllDeliveryArea($distributionMode){
        $polygonAll = Cache::get('polygonAllImportant');
        if(empty($polygonAll)){
            $deliverRegionData = Cache::get('warehouse_deliver_region_data');
            if(empty($deliverRegionData)){
                $deliverRegionData = $this->deliverRegion->getAllRegion();
                if($deliverRegionData){
                    Cache::forever('warehouse_deliver_region_data',$deliverRegionData,60);
                }
            }
            $polygonAll = [];
            if($deliverRegionData){
                foreach ($deliverRegionData as $regionValue){
                    foreach ($distributionMode as $modeKey=>$modelValue){
                        //return $modelValue->id;
                        if($regionValue['wdtype']==$modelValue->id){
                            $coordinates=Cache::get('warehouse_deliver_region_coordinates_'.$regionValue['id']);
                            if(empty($coordinates)){
                                $coordinates=$this->deliverRegionCoordinates->getRegionCoordinatesByRegionId($regionValue['id']);
                                if($coordinates){
                                    Cache::forever('warehouse_deliver_region_coordinates_'.$regionValue['id'],$coordinates,60);
                                }
                            }

                            if ($coordinates){
                                foreach ($coordinates as $coordinatesValue){
                                    if($coordinatesValue['latitude']>0&&$coordinatesValue['longitude']>0){
                                        $polygonAll[$modelValue->id][$regionValue['id']][] =[
                                            'lat'=>$coordinatesValue['latitude'],
                                            'lng'=>$coordinatesValue['longitude'],
                                            'wid'=>$regionValue['wid'],
                                            'modeKey'=>$modeKey,
                                            'wdr_id'=>$regionValue['id'],
                                            'mode_id'=>$modelValue->id,
                                            'name'=>$regionValue['name'],
                                            'start_price'=>(float)$regionValue['start_price']
                                        ];
                                    }
                                }
                            }else {
                                continue;
                            }
                        }
                    }
                }
                Cache::forever('polygonAllImportant',$polygonAll,60);
                return $polygonAll;
            }
        }else{
            return $polygonAll;
        }
    }


    /**
     * 射线法计算坐标是否在规定图形内
     * @param $polygon
     * @param $longitude
     * @param $latitude
     * @return bool
     */
    private function isPointInPolygon($polygon, $longitude, $latitude){
        $count = count($polygon);
        $px = $latitude;
        $py = $longitude;
        $flag = false;
        for ($i = 0, $j = $count - 1; $i < $count; $j = $i, $i++) {
            $sy = $polygon[$i]['lng'];
            $sx = $polygon[$i]['lat'];
            $ty = $polygon[$j]['lng'];
            $tx = $polygon[$j]['lat'];

            if ($px == $sx && $py == $sy || $px == $tx && $py == $ty){
                return true;
            }
            if ($sy < $py && $ty >= $py || $sy >= $py && $ty < $py) {
                $x = $sx + ($py - $sy) * ($tx - $sx) / ($ty - $sy);
                if ($x == $px)
                    return true;
                if ($x > $px)
                    $flag = !$flag;
            }
        }
        return $flag;
    }

}